import UIKit
@available(iOSApplicationExtension, unavailable)
public extension IQKeyboardManager {
    private static let  kIQDoneButtonToolbarTag         =   -1002
    private static let  kIQPreviousNextButtonToolbarTag =   -1005
    internal func addToolbarIfRequired() {
        guard let siblings = responderViews(), !siblings.isEmpty,
              let textField = textFieldView, textField.responds(to: #selector(setter: UITextField.inputAccessoryView)),
              (textField.inputAccessoryView == nil ||
                textField.inputAccessoryView?.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag ||
                textField.inputAccessoryView?.tag == IQKeyboardManager.kIQDoneButtonToolbarTag) else {
            return
        }
        let startTime = CACurrentMediaTime()
        showLog(">>>>> \(#function) started >>>>>", indentation: 1)
        showLog("Found \(siblings.count) responder sibling(s)")
        let rightConfiguration: IQBarButtonItemConfiguration
        if let doneBarButtonItemImage = toolbarDoneBarButtonItemImage {
            rightConfiguration = IQBarButtonItemConfiguration(image: doneBarButtonItemImage, action: #selector(self.doneAction(_:)))
        } else if let doneBarButtonItemText = toolbarDoneBarButtonItemText {
            rightConfiguration = IQBarButtonItemConfiguration(title: doneBarButtonItemText, action: #selector(self.doneAction(_:)))
        } else {
            rightConfiguration = IQBarButtonItemConfiguration(barButtonSystemItem: .done, action: #selector(self.doneAction(_:)))
        }
        rightConfiguration.accessibilityLabel = toolbarDoneBarButtonItemAccessibilityLabel ?? "Done"
        let isTableCollectionView: Bool
        if textField.superviewOfClassType(UITableView.self) != nil ||
            textField.superviewOfClassType(UICollectionView.self) != nil {
            isTableCollectionView = true
        } else {
            isTableCollectionView = false
        }
        let shouldHavePreviousNext: Bool
        switch previousNextDisplayMode {
        case .default:
            if isTableCollectionView {
                shouldHavePreviousNext = true
            } else if siblings.count <= 1 {
                shouldHavePreviousNext = false
            } else {
                shouldHavePreviousNext = true
            }
        case .alwaysShow:
            shouldHavePreviousNext = true
        case .alwaysHide:
            shouldHavePreviousNext = false
        }
        if shouldHavePreviousNext {
            let prevConfiguration: IQBarButtonItemConfiguration
            if let doneBarButtonItemImage = toolbarPreviousBarButtonItemImage {
                prevConfiguration = IQBarButtonItemConfiguration(image: doneBarButtonItemImage, action: #selector(self.previousAction(_:)))
            } else if let doneBarButtonItemText = toolbarPreviousBarButtonItemText {
                prevConfiguration = IQBarButtonItemConfiguration(title: doneBarButtonItemText, action: #selector(self.previousAction(_:)))
            } else {
                prevConfiguration = IQBarButtonItemConfiguration(image: (UIImage.keyboardPreviousImage() ?? UIImage()), action: #selector(self.previousAction(_:)))
            }
            prevConfiguration.accessibilityLabel = toolbarPreviousBarButtonItemAccessibilityLabel ?? "Previous"
            let nextConfiguration: IQBarButtonItemConfiguration
            if let doneBarButtonItemImage = toolbarNextBarButtonItemImage {
                nextConfiguration = IQBarButtonItemConfiguration(image: doneBarButtonItemImage, action: #selector(self.nextAction(_:)))
            } else if let doneBarButtonItemText = toolbarNextBarButtonItemText {
                nextConfiguration = IQBarButtonItemConfiguration(title: doneBarButtonItemText, action: #selector(self.nextAction(_:)))
            } else {
                nextConfiguration = IQBarButtonItemConfiguration(image: (UIImage.keyboardNextImage() ?? UIImage()), action: #selector(self.nextAction(_:)))
            }
            nextConfiguration.accessibilityLabel = toolbarNextBarButtonItemAccessibilityLabel ?? "Next"
            textField.addKeyboardToolbarWithTarget(target: self, titleText: (shouldShowToolbarPlaceholder ? textField.drawingToolbarPlaceholder: nil), titleAccessibilityLabel: toolbarTitlBarButtonItemAccessibilityLabel, rightBarButtonConfiguration: rightConfiguration, previousBarButtonConfiguration: prevConfiguration, nextBarButtonConfiguration: nextConfiguration)
            textField.inputAccessoryView?.tag = IQKeyboardManager.kIQPreviousNextButtonToolbarTag
            if isTableCollectionView {
                textField.keyboardToolbar.previousBarButton.isEnabled = true
                textField.keyboardToolbar.nextBarButton.isEnabled = true
            } else {
                textField.keyboardToolbar.previousBarButton.isEnabled = (siblings.first != textField)
                textField.keyboardToolbar.nextBarButton.isEnabled = (siblings.last != textField)
            }
        } else {
            textField.addKeyboardToolbarWithTarget(target: self, titleText: (shouldShowToolbarPlaceholder ? textField.drawingToolbarPlaceholder: nil), titleAccessibilityLabel: toolbarTitlBarButtonItemAccessibilityLabel, rightBarButtonConfiguration: rightConfiguration, previousBarButtonConfiguration: nil, nextBarButtonConfiguration: nil)
            textField.inputAccessoryView?.tag = IQKeyboardManager.kIQDoneButtonToolbarTag
        }
        let toolbar = textField.keyboardToolbar
        toolbar.tintColor = shouldToolbarUsesTextFieldTintColor ? textField.tintColor : toolbarTintColor
        if let textFieldView = textField as? UITextInput {
            switch textFieldView.keyboardAppearance {
            case .dark?:
                toolbar.barStyle = .black
                toolbar.barTintColor = nil
            default:
                toolbar.barStyle = .default
                toolbar.barTintColor = toolbarBarTintColor
            }
        }
        if shouldShowToolbarPlaceholder, !textField.shouldHideToolbarPlaceholder {
            if toolbar.titleBarButton.title == nil ||
                toolbar.titleBarButton.title != textField.drawingToolbarPlaceholder {
                toolbar.titleBarButton.title = textField.drawingToolbarPlaceholder
            }
            toolbar.titleBarButton.titleFont = placeholderFont
            toolbar.titleBarButton.titleColor = placeholderColor
            toolbar.titleBarButton.selectableTitleColor = placeholderButtonColor
        } else {
            toolbar.titleBarButton.title = nil
        }
        let elapsedTime = CACurrentMediaTime() - startTime
        showLog("<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
    }
    internal func removeToolbarIfRequired() {   
        guard let siblings = responderViews(), !siblings.isEmpty,
              let textField = textFieldView, textField.responds(to: #selector(setter: UITextField.inputAccessoryView)),
              (textField.inputAccessoryView == nil ||
                textField.inputAccessoryView?.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag ||
                textField.inputAccessoryView?.tag == IQKeyboardManager.kIQDoneButtonToolbarTag) else {
            return
        }
        let startTime = CACurrentMediaTime()
        showLog(">>>>> \(#function) started >>>>>", indentation: 1)
        showLog("Found \(siblings.count) responder sibling(s)")
        for view in siblings {
            if let toolbar = view.inputAccessoryView as? IQToolbar {
                if view.responds(to: #selector(setter: UITextField.inputAccessoryView)),
                    (toolbar.tag == IQKeyboardManager.kIQDoneButtonToolbarTag || toolbar.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag) {
                    if let textField = view as? UITextField {
                        textField.inputAccessoryView = nil
                    } else if let textView = view as? UITextView {
                        textView.inputAccessoryView = nil
                    }
                    view.reloadInputViews()
                }
            }
        }
        let elapsedTime = CACurrentMediaTime() - startTime
        showLog("<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
    }
    @objc func reloadInputViews() {
        if privateIsEnableAutoToolbar() {
            self.addToolbarIfRequired()
        } else {
            self.removeToolbarIfRequired()
        }
    }
}
@available(iOSApplicationExtension, unavailable)
public extension IQKeyboardManager {
    @objc var canGoPrevious: Bool {
        guard let textFields = responderViews(), let textFieldRetain = textFieldView, let index = textFields.firstIndex(of: textFieldRetain), index > 0 else {
            return false
        }
        return true
    }
    @objc var canGoNext: Bool {
        guard let textFields = responderViews(), let textFieldRetain = textFieldView, let index = textFields.firstIndex(of: textFieldRetain), index < textFields.count-1 else {
            return false
        }
        return true
    }
    @objc @discardableResult func goPrevious() -> Bool {
        guard let textFields = responderViews(), let textFieldRetain = textFieldView, let index = textFields.firstIndex(of: textFieldRetain), index > 0 else {
            return false
        }
        let nextTextField = textFields[index-1]
        let isAcceptAsFirstResponder = nextTextField.becomeFirstResponder()
        if isAcceptAsFirstResponder == false {
            showLog("Refuses to become first responder: \(nextTextField)")
        }
        return isAcceptAsFirstResponder
    }
    @objc @discardableResult func goNext() -> Bool {
        guard let textFields = responderViews(), let textFieldRetain = textFieldView, let index = textFields.firstIndex(of: textFieldRetain), index < textFields.count-1 else {
            return false
        }
        let nextTextField = textFields[index+1]
        let isAcceptAsFirstResponder = nextTextField.becomeFirstResponder()
        if isAcceptAsFirstResponder == false {
            showLog("Refuses to become first responder: \(nextTextField)")
        }
        return isAcceptAsFirstResponder
    }
    @objc internal func previousAction (_ barButton: IQBarButtonItem) {
        if shouldPlayInputClicks {
            UIDevice.current.playInputClick()
        }
        guard canGoPrevious, let textFieldRetain = textFieldView else {
            return
        }
        let isAcceptAsFirstResponder = goPrevious()
        var invocation = barButton.invocation
        var sender = textFieldRetain
        do {
            if let searchBar = textFieldRetain.textFieldSearchBar() {
                invocation = searchBar.keyboardToolbar.previousBarButton.invocation
                sender = searchBar
            }
        }
        if isAcceptAsFirstResponder {
            invocation?.invoke(from: sender)
        }
    }
    @objc internal func nextAction (_ barButton: IQBarButtonItem) {
        if shouldPlayInputClicks {
            UIDevice.current.playInputClick()
        }
        guard canGoNext, let textFieldRetain = textFieldView else {
            return
        }
        let isAcceptAsFirstResponder = goNext()
        var invocation = barButton.invocation
        var sender = textFieldRetain
        do {
            if let searchBar = textFieldRetain.textFieldSearchBar() {
                invocation = searchBar.keyboardToolbar.nextBarButton.invocation
                sender = searchBar
            }
        }
        if isAcceptAsFirstResponder {
            invocation?.invoke(from: sender)
        }
    }
    @objc internal func doneAction (_ barButton: IQBarButtonItem) {
        if shouldPlayInputClicks {
            UIDevice.current.playInputClick()
        }
        guard let textFieldRetain = textFieldView else {
            return
        }
        let isResignedFirstResponder = resignFirstResponder()
        var invocation = barButton.invocation
        var sender = textFieldRetain
        do {
            if let searchBar = textFieldRetain.textFieldSearchBar() {
                invocation = searchBar.keyboardToolbar.doneBarButton.invocation
                sender = searchBar
            }
        }
        if isResignedFirstResponder {
            invocation?.invoke(from: sender)
        }
    }
}
